package com.pjb.springbootjjwt.utils;

import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;

import com.pjb.springbootjjwt.annotation.BusinessException;
import com.pjb.springbootjjwt.entity.ClientidSecretModel;
import com.pjb.springbootjjwt.entity.User;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * jwt工具类
 */
@ConfigurationProperties(prefix = "jwt.config")
@Component
public class JwtUtils {
    private Logger logger = LoggerFactory.getLogger(getClass());

    private long expire;
    private String header;
    private List<ClientidSecretModel> secret;
    @Value("${jwt.config.signkey}")
    private String signkey;



    /**
     * 生成jwt token
     */
    public String generateToken(User user,String clientId,String secretKey,String timestamp) throws Exception  {


            // 校验clientId,secretKey,timestamp
            checkClientIdWithSecretKey(clientId,secretKey,timestamp);



        Date nowDate = new Date();
        Long v = expire;
        //过期时间
        Date expireDate = new Date(nowDate.getTime() + v * 1000);
        HashMap<String, Object> extraParams = new HashMap<>();
        extraParams.put("secretKey",secretKey);
        extraParams.put("clientid",clientId);
        extraParams.put("timestamp",timestamp);
        extraParams.put("userid",user.getId());
        HashMap<String, Object> header = new HashMap<>();
        header.put("typ","JWT");
        return JWT.create()
            .withHeader(header)
            .withSubject(user.getUsername())
            .withAudience(JSON.toJSONString(extraParams))
            .withIssuedAt(nowDate)
            .withExpiresAt(expireDate)
            .sign(Algorithm.HMAC512(signkey.getBytes(StandardCharsets.UTF_8)) );

    }

    /**
     *  校验clientid和secretkey
     *  */
    public void checkClientIdWithSecretKey(String clientid,String secretKey,String timestamp) throws BusinessException  {
        if(StringUtils.isEmpty(clientid)||StringUtils.isEmpty(secretKey)||StringUtils.isEmpty(timestamp)){
            logger.error("clientid||secretKey||timestamp不能为空");
                throw new BusinessException("clientid||secretKey||timestamp不能为空");


        }
        boolean flag = false;

        for (ClientidSecretModel secretModel : secret) {
            if(secretModel.getClientid().equals(clientid)&&secretModel.getSecretKey().equals(secretKey)){
                flag =true;
            }
        }
        if(!flag){
                throw new BusinessException("clientid和secretkey不匹配或者异常");

        }
    }


    /**
     * 校验token是否有错
     * @param token
     */
    public void verify(String token) throws BusinessException {
        try {
            JWTVerifier build = JWT.require(Algorithm.HMAC512(signkey)).build();
            build.verify(token);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            throw new BusinessException("token解析失败，请确认token是否填写有误");
        } catch (JWTVerificationException e) {
            e.printStackTrace();
            throw new BusinessException("token解析失败，请确认token是否填写有误");
        }
    }
    /**
     * token是否过期
     * @return  true：过期
     */
    public void isTokenExpired(String token) throws BusinessException {
//        Claims body = null;
//            body = Jwts.parser().setSigningKey(secret)
//                .parseClaimsJws(token)
//                .getBody();
        DecodedJWT decode = JWT.decode(token);
        Date expiresAt = decode.getExpiresAt();
        if(expiresAt.before(new Date())){
            throw new BusinessException("token已经超时");
        }
    }

    public List<ClientidSecretModel> getSecret() {
        return secret;
    }

    public void setSecret(List<ClientidSecretModel> secret) {
        this.secret = secret;
    }

    public long getExpire() {
        return expire;
    }

    public void setExpire(long expire) {
        this.expire = expire;
    }

    public String getHeader() {
        return header;
    }

    public void setHeader(String header) {
        this.header = header;
    }

}
